﻿using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Banks;
using mozhi.smarterp.Finance.Banks.Repository;
using mozhi.smarterp.Finance.Basedatas;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Finances;
using mozhi.smarterp.Finance.Finances.Repository;
using mozhi.smarterp.Finance.Querys;
using Mozhi.Abp.Core.Extensions;
using Mozhi.Abp.Domain.BasicData;
using Mozhi.Abp.Domain.BasicData.Repositories;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Guids;

namespace mozhi.smarterp.Finance.Accounts
{
    public class AccountManager : DomainServiceBase
    {
        private IAccountRepository _accountRepository;
        private IAccountDimensionRepository _dimensionRepository;
        private IGuidGenerator _guidGenerator;
        private IBankAccountRepository _bankAccountRepository;
        private IAccountBalanceRepository _accountBalanceRepository;
        private IJournalRepository _journalRepository;
        private ICustomerRepository _customerRepository;
        private ISupplierRepository _supplierRepository;
        private IEmployeeRepository _employeeRepository;
        //private IExpenseItemRepository _expenseItemRepository;
        private IProductRepository _productRepository;
        private IDimensionGroupValueRepository _dimensionGroupValueRepository;
        private IOrganizationRepository _organizationRepository;
        

        public AccountManager(IAccountRepository accountRepository, IGuidGenerator guidGenerator, IAccountDimensionRepository dimensionRepository,
            IBankAccountRepository bankAccountRepository, IAccountBalanceRepository accountBalanceRepository, IJournalRepository journalRepository,
            ICustomerRepository customerRepository,ISupplierRepository supplierRepository , 
            IEmployeeRepository employeeRepository,IProductRepository productRepository,
            IDimensionGroupValueRepository dimensionGroupValueRepository,
            IOrganizationRepository organizationRepository, IDataAssociationRepository associationRepository) :base(associationRepository)
        {
            _accountRepository = accountRepository;
            _guidGenerator = guidGenerator;
            _dimensionRepository = dimensionRepository;
            _bankAccountRepository = bankAccountRepository;
            _accountBalanceRepository = accountBalanceRepository;
            _organizationRepository = organizationRepository;
            _journalRepository = journalRepository;
            _customerRepository = customerRepository;
            _supplierRepository = supplierRepository;
            //_thirdPartyRepository = thirdPartyRepository;
            _employeeRepository = employeeRepository;
            //_expenseItemRepository = expenseItemRepository;
            _productRepository = productRepository;
            _dimensionGroupValueRepository = dimensionGroupValueRepository;
        }

        public async Task<Tuple<Account, Account, List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>> CreateAsync(Guid? parentId, string code, string name,
            AccountType accountType, AccountDirectionType direction,
            bool isFundAccount, Guid? bankAccoutId , List<AccountDimensionItem> dimensionItems)
        {

            await ValidateDuplicate(code, name);

            var parent = await ValidateParentAccount(parentId);

            var account = new Account(_guidGenerator.Create(), code, name, accountType, direction);

            Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>> firstChildAccountTuple = null;

            if (parent != null)
            {
                account.SetParent(parent);

                await SetAccountDimensionItems(account, parent, dimensionItems);

                parent.SetLevel(false);

                var childCount = await _accountRepository.GetCountAsync(null , null , null , null , null , parent.Id);

                //第一个子级科目处理逻辑
                if (childCount == 0)
                    firstChildAccountTuple = await AddFirstChildAccount(parent, account);
            }

            if (isFundAccount)
                await ChangeBankAccount(account, bankAccoutId.Value);

            var balances = firstChildAccountTuple != null ? firstChildAccountTuple.Item1 : new List<AccountBalance>();

            var journals = firstChildAccountTuple != null ? firstChildAccountTuple.Item2 : new List<Journal>();

            var baseDataDict = firstChildAccountTuple != null ? firstChildAccountTuple.Item3 : new Dictionary<string, List<object>>();

            var result = new Tuple<Account, Account, List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>(account, parent, balances, journals, baseDataDict);

            return result;
        }

      
        public async Task<Account> UpdateAsync(Guid id, string code, string name, AccountDirectionType direction, bool activated,
            Guid? bankAccountId, bool isForeignCurrency , List<AccountDimensionItem> dimensionItems)
        {
            var account = await _accountRepository.GetAsync(id, true);

            if (account == null)
                throw new UserFriendlyException("科目不存在", "100000");

            await ValidateDuplicate(code, name, account.Id);

            account.ChangeBaseInfo(code, name , null);

            await ChangeDirection(account, direction);

            await ChangeForeignCurrency(account, isForeignCurrency);

            await ChangeBankAccount(account, bankAccountId);

            account.SetStatus(activated);

            await SetAccountDimensionItems(account, null , dimensionItems);

            return account;
        }


        public async Task<Tuple<Account, Account, List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>> DeleteAsync(Guid id)
        {
            var account = await _accountRepository.GetAsync(id);

            if (account == null)
                throw new UserFriendlyException("科目不存在", "100000");

            //查找引用
            var associations = await GetDataAssociationDetail(id);

            if (associations.Count > 0)
                throw new UserFriendlyException($"科目存在引用：{string.Join(",", associations)}，无法删除", "100000");

            var parent = await ValidateParentAccount(account.ParentId);

            Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>> firstChildAccountTuple = null;

            if (parent != null)
            {
                var childCount = await _accountRepository.GetCountAsync(null, null, null, null, null, parent.Id);

                if (childCount == 1)
                    firstChildAccountTuple = await RemoveFirstChildAccount(parent, account);
            }

            var balances = firstChildAccountTuple != null ? firstChildAccountTuple.Item1 : new List<AccountBalance>();

            var journals = firstChildAccountTuple != null ? firstChildAccountTuple.Item2 : new List<Journal>();

            var baseDataDict = firstChildAccountTuple != null ? firstChildAccountTuple.Item3 : new Dictionary<string, List<object>>();

            var result = new Tuple<Account, Account, List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>(account, parent, balances, journals, baseDataDict);

            return result;
        }


        public async Task<AccountDimensionItem> CreateDimensionItem(Guid dimenssionId, bool required, bool activated)
        {
            var dimension = await _dimensionRepository.FindAsync(dimenssionId);

            if (dimension == null)
                throw new UserFriendlyException("核算维度不存在", "100000");

            if (!dimension.Activated)
                throw new UserFriendlyException("核算维度已禁用", "100000");

            return new AccountDimensionItem(_guidGenerator.Create(), dimenssionId, required, dimension.Name, activated);
        }

        public async Task ValidateDuplicate(string code, string name, Guid? currentId = null)
        {
            var codeExistCount = await _accountRepository.GetCountAsync(null , code ,null , null , currentId , null);

            if (codeExistCount > 0)
                throw new UserFriendlyException("科目编码已存在", "100000");

            var nameExistCount = await _accountRepository.GetCountAsync(null, null, name, null, currentId, null);

            if (nameExistCount > 0)
                throw new UserFriendlyException("科目名称已存在", "100000");
        }

        public async Task ChangeDirection(Account account, AccountDirectionType direction)
        {
            if (account.Direction == direction)
                return;

            //第一个子级科目不允许更改方向
            if (account.ParentId.HasValue)
            {
                var childCount = await _accountRepository.GetCountAsync(null, null, null, null, null, account.ParentId);

                if (childCount == 0)
                    throw new UserFriendlyException("第一个子级科目不允许更改科目余额方向", "100000");
            }

            //存在余额和凭证，不能更改科目方向
            var balanceCount = await _accountBalanceRepository.GetCountAsync(new AccountBalanceQuery() { AccountIds = new List<Guid> { account.Id } });

            var journalCount = await _journalRepository.GetCountAsync(new JournalPageQuery() { AccountIds = new List<Guid>() { account.Id }, PageIndex = 1, PageSize = int.MaxValue });

            if (balanceCount > 0)
                throw new UserFriendlyException("科目存在余额，无法更改科目方向", "100000");

            if (journalCount > 0)
                throw new UserFriendlyException("科目存在凭证，无法更改科目方向", "100000");

            account.SetDirection(direction);
        }

        public async Task ChangeForeignCurrency(Account account, bool isForeignCurrency)
        {
            if (account.IsForeignCurrencyAccounting == isForeignCurrency)
                return;

            //存在外币余额和外币凭证，不能科目的外币核算
            var balanceCount = await _accountBalanceRepository.GetCountAsync(new AccountBalanceQuery() { AccountIds = new List<Guid> { account.Id }, IncludeCurrency = true });

            var journalCount = await _journalRepository.GetCountAsync(new JournalPageQuery() { AccountIds = new List<Guid>() { account.Id }, PageIndex = 1, PageSize = int.MaxValue }); ;

            if (balanceCount > 0)
                throw new UserFriendlyException("科目存在外币余额，无法更改为非外币核算", "100000");

            if (journalCount > 0)
                throw new UserFriendlyException("科目存在外币余额，无法更改为非外币核算", "100000");

            account.SetForeignCurrency(isForeignCurrency);
        }

        public async Task ChangeBankAccount(Account account, Guid? bankAccountId)
        {
            //if (account.BankAccountId == bankAccountId)
            //    return;

            //BankAccount bankAccount = null;

            //if (bankAccountId.HasValue)
            //{
            //    bankAccount = await _bankAccountRepository.FindAsync(bankAccountId.Value);

            //    if (bankAccount == null)
            //        throw new UserFriendlyException("银行账号不存在", "100000");
            //}

            ////检查银行账号是否已经绑定
            //var bankBindCount = await _accountRepository.GetCountAsync(new AccountQuery { BankAccountId = bankAccountId, ExclusionId = account.Id });

            //if (bankBindCount > 0)
            //    throw new UserFriendlyException("银行账号已经绑定其他科目，不允许绑定", "100000");

            //account.BindBankAccount(bankAccount);
            throw new NotImplementedException();
        }


        public async Task SetAccountDimensionItems(Account account, Account parent, List<AccountDimensionItem> dimensionItems)
        {
            dimensionItems = dimensionItems ?? new List<AccountDimensionItem>();

            var childCount = parent == null ? 1 : await _accountRepository.GetCountAsync(null, null, null, null, null, parent.Id);

            //第一个子级科目，需要继承父级的
            if (childCount == 0)
            {
                var parentDimenssions = parent.DimensionItems;

                foreach (var parentDimensionItem in parentDimenssions)
                {
                    if (!dimensionItems.Exists(x => x.DimensionId == parentDimensionItem.DimensionId))
                    {
                        var added = new AccountDimensionItem(account.Id, parentDimensionItem.DimensionId, parentDimensionItem.IsRequire, parentDimensionItem.DimensionName, parentDimensionItem.Activated);

                        dimensionItems.Add(added);
                    }
                }
            }

            //余额和凭证有没有引用核算维度内容，如果有的话，不允许删除和更改
            var balances = await _accountBalanceRepository.FindAsync(new AccountBalanceQuery() { AccountIds = new List<Guid> { account.Id }, IncludeDimension = true });

            var dimensionGroupValueIds = balances.Where(x => x.DimensionGroupValueId.HasValue).Select(x => x.DimensionGroupValueId.Value).Distinct().ToList();

            var journals = await _journalRepository.FindAsync(new JournalPageQuery() { AccountIds = new List<Guid>() { account.Id }, PageIndex = 1, PageSize = int.MaxValue, IncludeDetail = true });

            var journalDimensionGroupValueIds = journals.Select(x => x.Items).ToList().Join().Where(x => x.AccountId == account.Id).ToList().Where(x => x.DimensionGroupValueId.HasValue).Select(x => x.DimensionGroupValueId.Value).ToList();

            dimensionGroupValueIds.AddRange(journalDimensionGroupValueIds);

            var dimensionGroupValues = await _dimensionGroupValueRepository.FindAsync(new DimensionGroupValuePageQuery() { Ids = dimensionGroupValueIds, IncludeDetail = true });

            var dimensionGroupValueItems = dimensionGroupValues.Where(x => x.Items != null).Select(x => x.Items).ToList().Join().ToList();

            //先找设置的科目核算维度必录，是不是在原来的余额和凭证核算维度都有值
            var matchRequiredItems = dimensionItems.Where(x => x.IsRequire == true).ToList();

            var dimensions = await _dimensionRepository.FindAsync(new PageQuery() { Ids = dimensionItems.Select(x => x.DimensionId).ToList(), PageIndex = 1, PageSize = int.MaxValue });

            foreach (var requiredItem in matchRequiredItems)
            {
                var matchDimension = dimensions.FirstOrDefault(x => x.Id == requiredItem.DimensionId);

                if (matchDimension == null)
                    throw new BusinessException("100000", $"核算维度不存在:{requiredItem.DimensionId}");

                var matchValueItems = dimensionGroupValueItems.Where(x => x.DataSourceType == matchDimension.DataSourceType).ToList();

                if (matchValueItems.Count == 0 || matchValueItems.Exists(x => x.Value.IsNullOrEmpty()))
                    throw new UserFriendlyException($"科目存在余额或者凭证，无法将核算维度：{matchDimension.Name}设置为必录");
            }

            //然后找移除的维度
            var dimensionItemIds = dimensionItems.Select(x => x.DimensionId);

            var removedDimensionItems = account.DimensionItems.Where(x => !dimensionItemIds.Contains(x.DimensionId)).ToList();

            foreach (var removedDimensionItem in removedDimensionItems)
            {
                var matchDimension = dimensions.FirstOrDefault(x => x.Id == removedDimensionItem.DimensionId);

                if (matchDimension == null)
                    throw new BusinessException("100000", $"核算维度不存在:{removedDimensionItem.DimensionId}");

                var matchValueItems = dimensionGroupValueItems.Where(x => x.DataSourceType == matchDimension.DataSourceType).ToList();

                if (matchValueItems.Count > 0)
                    throw new UserFriendlyException($"科目存在余额或者凭证，无法将核算维度：{matchDimension.Name}设置移除");
            }

            account.SetDimensionItems(dimensionItems);
        }


        public async Task<Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>> AddFirstChildAccount(Account parent, Account child)
        {
            var childCount = await _accountRepository.GetCountAsync(null, null, null, null, null, parent.Id);

            if (childCount != 0)
                throw new UserFriendlyException("当前新增的科目非第一个子级科目", "100000");

            //校验1.如果是银行科目，不允许更改标记 2父级存在余额，不允许更改方向 3.存在余额，不允许更改删除父级的核算维度,4.存在余额，不允许更改外币核算属性

            if (parent.Direction != child.Direction)
                throw new UserFriendlyException("新增第一个子级科目，父级科目和子级科目的方向要一致", "100000");

            var parentBalanceCount = await _accountBalanceRepository.GetCountAsync(new AccountBalanceQuery() { AccountIds = new List<Guid>() { parent.Id } });

            if (parentBalanceCount > 0 && parent.GetDimensionItemHashCode() != child.GetDimensionItemHashCode())
                throw new UserFriendlyException("新增第一个子级科目，存在科目余额，不允许更改核算维度信息", "100000");

            if (parentBalanceCount > 0 && parent.IsForeignCurrencyAccounting && !child.IsForeignCurrencyAccounting)
                throw new UserFriendlyException("新增第一个子级科目，存在科目余额，不允许更改外币核算属性", "100000");

            //1更改基础资料科目的数据
            var dictBaseData = await ReplaceBaseDataAccount(parent, child);

            //2 更改科目余额表数据，将父级科目的余额信息带入子级科目，同时将父级科目带核算维度的余额清除掉
            var balances = await ReplaceBalanceAccount(parent, child);

            //3 更改凭证的科目数据
            var journals = await ReplaceJournalAccount(parent, child);

            return new Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>(balances, journals, dictBaseData);
        }


        public async Task<Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>> RemoveFirstChildAccount(Account parent, Account child)
        {
            //需要校验是不是第一个子级科目移除
            var childCount = await _accountRepository.GetCountAsync(null, null, null, null, null, parent.Id);

            if (childCount != 1)
                throw new UserFriendlyException("当前移除的科目非第一个子级科目", "100000");

            //需要将子级的信息还原到父级
            //1.银行科目信息
            //if (child.BankAccountId.HasValue)
            //{
            //    var bankAccount = await _bankAccountRepository.GetAsync(child.BankAccountId.Value);

            //    parent.BindBankAccount(bankAccount);
            //}
            //2.基础资料引用科目的地方还原
            var basedataDict = await ReplaceBaseDataAccount(child, parent);

            //3.余额还原(只需要还原带附加属性的余额)
            var balances = await ReplaceBalanceAccount(child, parent);

            //4.凭证还原
            var journals = await ReplaceJournalAccount(child, parent);

            //5.修改父级科目信息,并继承子级科目的核算维度
            parent.SetLevel(true);

            var dimensionItems = child.DimensionItems;

            dimensionItems.ForEach(item =>
            {
                item.SetAccountId(parent.Id);
            });
            parent.SetDimensionItems(dimensionItems);

            return new Tuple<List<AccountBalance>, List<Journal>, Dictionary<string, List<object>>>(balances, journals, basedataDict);
        }

        public List<Account> GetChildAccounts(Guid parentId , List<Account> accounts)
        {
            var children = accounts.Where(x=>x.ParentId == parentId).ToList();

            if (children.Count == 0)
                return children;

            foreach(var child in children)
            {
                var tempChildren = GetChildAccounts(child.Id, accounts);

                children.AddRange(tempChildren);
            }

            return children;
        }


        #region
        private async Task<Account> ValidateParentAccount(Guid? parentId)
        {
            if (!parentId.HasValue)
                return null;

            var parentAccount = await _accountRepository.FindAsync(parentId.Value , true);

            if (parentAccount == null)
                throw new UserFriendlyException("上级科目不存在", "100000");

            if (!parentAccount.Activated)
                throw new UserFriendlyException("上级科目已禁用，不允许新增子级科目", "100000");

            return parentAccount;
        }

        private async Task<Dictionary<string, List<object>>> ReplaceBaseDataAccount(Account source, Account target)
        {
            var result = new Dictionary<string, List<object>>();

            var customers = new List<Customer>(); //await _customerRepository.FindAsync(new BaseDataPageQuery() { PageIndex = 1, PageSize = int.MaxValue, AccountId = source.Id });

            if (customers.Count > 0)
            {
                var dictKey = "Customer";
                var dictValues = new List<object>();

                //foreach (var customer in customers)
                //{
                //    var newReceivableAccountId = customer.ReceivableAccountId == source.Id ? target.Id : customer.ReceivableAccountId;
                //    var newPrereceiveAccountId = customer.PrereceiveAccountId == source.Id ? target.Id : customer.PrereceiveAccountId;

                //    customer.ChangeAccount(newReceivableAccountId, newPrereceiveAccountId);

                //    dictValues.Add(customer);
                //}

                result.Add(dictKey, dictValues);
            }

            var suppliers = new List<Supplier>(); //await _supplierRepository.FindAsync(new BaseDataPageQuery() { AccountId = source.Id, PageIndex = 1, PageSize = int.MaxValue });

            if (suppliers.Count > 0)
            {
                var dictKey = "Supplier";
                var dictValues = new List<object>();

                foreach (var supplier in suppliers)
                {
                    //var newPayableAccountId = supplier.PayableAccountId == source.Id ? target.Id : supplier.PayableAccountId;
                    //var newPrepaymentAccountId = supplier.PrepaymentAccountId == source.Id ? target.Id : supplier.PrepaymentAccountId;

                    //supplier.ChangeAccount(newPayableAccountId, newPrepaymentAccountId);

                    dictValues.Add(supplier);
                }

                result.Add(dictKey, dictValues);
            }


            var employees = new List<Employee>(); // await _employeeRepository.FindAsync(new BaseDataPageQuery() { AccountId = source.Id, PageIndex = 1, PageSize = int.MaxValue });

            if (employees.Count > 0)
            {
                var dictKey = "Employee";
                var dictValues = new List<object>();

                //foreach (var employee in employees)
                //{
                //    employee.ChangeAccount(target.Id);

                //    dictValues.Add(employee);
                //}

                result.Add(dictKey, dictValues);
            }

            //var expenseItems = await _expenseItemRepository.FindAsync(new ExpenseItemPageQuery() { AccountId = source.Id, PageIndex = 1, PageSize = int.MaxValue });

            //if (expenseItems.Count > 0)
            //{
            //    var dictKey = "ExpenseItem";
            //    var dictValues = new List<object>();

            //    foreach (var expenseItem in expenseItems)
            //    {
            //        expenseItem.Change(expenseItem.ParentId, target.Id, expenseItem.IsLeaf);

            //        dictValues.Add(expenseItem);
            //    }

            //    result.Add(dictKey, dictValues);
            //}

            var products = new List<Product>(); // await _productRepository.FindAsync(new BaseDataPageQuery() { AccountId = source.Id, PageIndex = 1, PageSize = int.MaxValue });
            if (products.Count > 0)
            {
                var dictKey = "Product";
                var dictValues = new List<object>();

                //foreach (var product in products)
                //{
                //    var newStockAccountId = product.StockAccountId == source.Id ? target.Id : product.StockAccountId;
                //    var newRevenueAccountId = product.RevenueAccountId == source.Id ? target.Id : product.RevenueAccountId;
                //    var newCostAccountId = product.CostAccountId == source.Id ? target.Id : product.CostAccountId;
                //    var newExpenseAccountId = product.ExpenseAccountId == source.Id ? target.Id : product.ExpenseAccountId;

                //    product.ChangeAccount(product.Type, newStockAccountId, newRevenueAccountId, newCostAccountId, newExpenseAccountId);

                //    dictValues.Add(product);
                //}

                result.Add(dictKey, dictValues);
            }

            return result;
        }


        private async Task<List<Journal>> ReplaceJournalAccount(Account source , Account target)
        {
            var journals = await _journalRepository.FindAsync(new JournalPageQuery() { AccountIds = new List<Guid>() { source.Id }, IncludeDetail = true, PageIndex = 1, PageSize = int.MaxValue });

            foreach (var journal in journals)
            {
                var matchJournalItems = journal.Items.Where(x => x.AccountId == source.Id).ToList();

                if (matchJournalItems.Count == 0)
                    continue;

                matchJournalItems.ForEach(item =>
                {
                    item.ChangeAccount(target.Id);
                });
            }

            return journals;
        }

        private async Task<List<AccountBalance>> ReplaceBalanceAccount(Account source , Account target)
        {
            var result = new List<AccountBalance>();

            var sourceBalances = await _accountBalanceRepository.GetAsync(new AccountBalanceQuery() { AccountIds = new List<Guid>() { source.Id } });

            if (sourceBalances.Count == 0)
                return result;

            var targetBalances = new List<AccountBalance>();

            var organization = await _organizationRepository.GetAsync();

            var baseCurrencyId = organization.StandardCurrencyId.Value;

            //var bankAccount = source.BankAccountId.HasValue ? await _bankAccountRepository.FindAsync(source.BankAccountId.Value) : null;

            foreach (var sourceBalance in sourceBalances)
            {
                var targetBalance = new AccountBalance(_guidGenerator.Create(), target.Id, sourceBalance.CurrencyId, sourceBalance.Period, sourceBalance.DimensionGroupValueId, target.Direction);

                //targetBalance.ChangeAmount(target.IsForeignCurrency, baseCurrencyId, bankAccount?.CurrencyId, sourceBalance.OpeningAmount, sourceBalance.OpeningAmountFr,
                //    sourceBalance.CurrentYearDebitAmount, sourceBalance.CurrentYearDebitAmountFr, sourceBalance.CurrentYearCreditAmount, sourceBalance.CurrentYearCreditAmountFr,
                //    sourceBalance.DebitAmount, sourceBalance.DebitAmountFr, sourceBalance.CreditAmount, sourceBalance.CreditAmountFr);

                targetBalances.Add(targetBalance);
            }

            var sourceDeletedBalances = targetBalances.Where(x => x.DimensionGroupValueId.HasValue).ToList();

            targetBalances.AddRange(sourceDeletedBalances);
            
            return targetBalances;
        }

        #endregion

    }
}
